#include "stm32f10x.h"                  // Device header


/************************************************************************************************************
* Function name : MySPI_W_SS
* Description   : 拉高 或 拉低 SS 线
* Parameter     : 
* Return        : 
************************************************************************************************************/
void MySPI_W_SS(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOA, GPIO_Pin_4, (BitAction)BitValue);
}


/************************************************************************************************************
* Function name : MySPI_Init
* Description   : 初始化 SPI 的通信引脚
* Parameter     : 
* Return        : 
************************************************************************************************************/
void MySPI_Init(void)
{
	
	/********************************** 第一步：开启 GPIO (SS 引脚) 和 SPI 外设的时钟，均在 APB2 总线上。 ****************************/
	
	// 打开 APB2 的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);

	/********************************** 第二步：初始化 GPIO 口  ****************************/
	
	// SS 引脚配置
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;                     // 通用推挽输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;                            // SS 引脚配置成通用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                    // 输出速度没有特殊要求选择 50MHz 即可
	GPIO_Init(GPIOA, &GPIO_InitStructure);    
	
	// SCK 和 MOSI
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                      // 复用推挽输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;               //  
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                    // 输出速度没有特殊要求选择 50MHz 即可
	GPIO_Init(GPIOA, &GPIO_InitStructure);    

	// MISO 引脚
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;                        // 复用推挽输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;                            //  
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                    // 输出速度没有特殊要求选择 50MHz 即可
	GPIO_Init(GPIOA, &GPIO_InitStructure);    
	
	
	/********************************** 第三步：配置 SPI 外设，这一块使用一个结构体参数即可。  ****************************/
	SPI_InitTypeDef SPI_InitStructure;
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;  // 72MHz / 128
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;                          // 第几个边沿采样
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;                            // 极性选择
	SPI_InitStructure.SPI_CRCPolynomial = 7;                              // CRC 校验参数, 给个默认值 7 即可
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;                     // 
	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;    // 双线全双工
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;                    // 高位先行
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;                         // 表示主机还是从机
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                             // 使用GPIO来充当 NSS, 配置成 Soft 即可.
	SPI_Init(SPI1, &SPI_InitStructure);
	
	
	/********************************** 第四步：使能 SPI 外设  ****************************/
	SPI_Cmd(SPI1, ENABLE);

	// 置一下初始化引脚的默认电平: 
	// SS 置为高电平,  SCK 在模式0时默认低电平, MOSI 无规定, MISO 输入引脚不用管
	MySPI_W_SS(1);

}


/************************************************************************************************************
* Function name : MySPI_Start
* Description   : 起始信号, SS 置为低电平即可
* Parameter     : 
* Return        : 
************************************************************************************************************/
void MySPI_Start(void)
{
	MySPI_W_SS(0);
}


/************************************************************************************************************
* Function name : MySPI_Start
* Description   : 终止信号, SS 置为高电平即可
* Parameter     : 
* Return        : 
************************************************************************************************************/
void MySPI_Stop(void)
{
	MySPI_W_SS(1);
}


/************************************************************************************************************
* Function name : MySPI_SwapByte
* Description   : 交换字节 
* Parameter     : 
* Return        : 
************************************************************************************************************/
uint8_t MySPI_SwapByte(uint8_t ByteSend)
{
	// 检测到 TXE 为空跳出循环
	while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) != SET)
	;
	
	// 软件写入数据至 SPI_DR: 一旦移位寄存器有数据, 则会自动产生波形, 并会自动清除 TXE
	SPI_I2S_SendData(SPI1, ByteSend);
	
	// 等待 RXNE 为 1
	while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) != SET)
	;
	
	// 读取 RDR, 并自动会清除 RXNE
	return SPI_I2S_ReceiveData(SPI1);
}